/**
 * \file utf8.h
 * \brief Basic functions for handling UTF-8 encoded text. Note that you can
 * also easily read out Unicode code-points, which are 32-bit unsigned
 * integers.
 **/

#ifndef R_UTF8_H
#define R_UTF8_H

#include "standard.h"
#include "codes.h"

/**
 * \typedef uni_char
 * \brief This is a 32-bit Unicode code-point.
 **/
typedef uint32_t uni_char;

/**
 * \brief Tells you if the given octet is in the ascii range (Unicode
 * 00 through 7F).
 **/
#define r_utf8_is_ascii(c) (!(0x80 & (c)))

/**
 * \brief Tells you if the given octet is in the middle of a UTF-8 encoded
 * character.
 **/
#define r_utf8_in_middle(c) (((c) & 0xC0) == 0x80)

/**
 * \brief Tells you if the given octet is starting a 2-character UTF-8
 * encoded sequence (Unicode 0080 through 07FF).
 **/
#define r_utf8_is_start2(c) (((c) & 0xE0) == 0xC0)

/**
 * \brief Tells you if the given octet is starting a 3-character UTF-8
 * encoded sequence (Unicode 0800 through D7FF and E000 through FFFF).
 **/
#define r_utf8_is_start3(c) (((c) & 0xF0) == 0xE0)

/**
 * \brief Tells you if the given octet is starting a 4-character UTF-8
 * encoded sequence (Unicode 010000 through 10FFFF).
 **/
#define r_utf8_is_start4(c) (((c) & 0xF8) == 0xF0)

/**
 * \brief Tells you how many octets are needed to encode the given #uni_char.
 * This assumes a valid uni_char (r_utf_valid_uni_char()).
 **/
#define r_utf8_needs(u) (((u) <= 0x7F) ? 1 : \
                          (((u) <= 0x7FF) ? 2 : \
                           (((u) <= 0xFFFF) ? 3 : 4) \
                          ) \
                         )

/**
 * \brief Reads one #uni_char from the buffer given in #str, taking care
 * not to read byte at #limit or beyond it. The read #uni_char is placed
 * into the position given by #dest.
 * \return #R_SUCCESS (0), #R_UTF8_SEEK, #R_UTF8_INVALID or
 * #R_UTF8_LIMITED.
 **/
int r_utf8_read_uni_char(uint8_t** str, uint8_t* limit, uni_char* dest);

/**
 * \brief Verifies if a #uni_char is not bigger than the allowed Unicode
 * range. This does not check for the Unicode range D800 through DFFF,
 * which is not allowed (but correctly encoded using UTF-8).
 **/
#define r_utf8_valid_uni_char(u) ((u) <= 0x10FFFF)

/**
 * \brief Write one #uni_char to the buffer given in #str, taking care
 * not to write the byte at #limit or beyond it.
 * \return #R_SUCCESS, #R_UTF8_INVALID (given uni_char is invalid, beyond
 * 0x10FFFF) or #R_UTF8_LIMITED (need to write more bytes than allowed by
 * the limit.
 **/
int r_utf8_write_uni_char(uint8_t** str, uint8_t* limit, uni_char c);

#endif /* R_UTF8_H */
